Popular Searches
Popular Course Categories
Popular Courses

ES6+ Features: Spread, Rest, Template Literals, and Modules

ES6+ Features: Spread, Rest, Template Literals, and Modules

JavaScript and Modern ES6+ Fundamentals

ES6+ Features: Spread, Rest, Template Literals, and Modules

Course: React Native Training

Topic: ES6+ Features: Spread, Rest, Template Literals, and Modules

Course Link: React Native Training Course

Demo Link: Register for a Free Course Demo

Official Website: JustAcademy


1. Introduction to ES6+ Features

ES6, also known as ECMAScript 2015, introduced several important improvements to JavaScript. These features make code more readable, reusable, concise, and easier to maintain. Later ECMAScript versions introduced additional improvements that are commonly grouped under the term ES6+.

ES6+ features are particularly useful in React Native development because applications frequently work with arrays, objects, component props, state, API responses, and reusable modules.

1.1 What Is ECMAScript?

ECMAScript is the language specification on which JavaScript is based. JavaScript engines implement ECMAScript features to provide the language capabilities developers use when building web and mobile applications.

1.2 Important ES6+ Features

Feature Purpose Example
Spread operator Expands elements or properties from arrays and objects. [...numbers]
Rest parameter Collects multiple arguments into an array. function sum(...values)
Template literals Embed expressions and create multiline strings. `Hello ${name}`
Modules Organize code into reusable files. export and import
Destructuring Extract values from arrays and objects. const {name} = user
Arrow functions Write concise function expressions. const add = (a, b) => a + b
Optional chaining Safely access potentially missing properties. user?.profile?.name
Default parameters Provide default values for function parameters. function greet(name = "Guest")

2. Learning Objectives

After completing this topic, learners should be able to:

  • Understand the purpose of modern JavaScript features.
  • Use the spread operator with arrays and objects.
  • Use rest parameters and distinguish them from spread syntax.
  • Create dynamic strings using template literals.
  • Understand named exports, default exports, and imports.
  • Organize React Native applications into reusable modules.
  • Use spread syntax to update arrays and objects immutably.
  • Apply ES6+ features when working with React Native props, state, and API data.
  • Recognize common mistakes and follow modern JavaScript best practices.

3. The Spread Operator

The spread operator uses three dots (...) to expand the elements of an iterable or the enumerable properties of an object into another expression. It is commonly used with arrays, objects, and function calls.

3.1 Spread Operator with Arrays

The spread operator can expand the elements of an array into a new array.

const numbers = [10, 20, 30];
const copiedNumbers = [...numbers];
console.log(copiedNumbers);
// [10, 20, 30]

Here, ... expands the elements of numbers into the new array. The new array is a different array from the original.

3.2 Combining Arrays

Spread syntax makes it easy to combine multiple arrays.

const first = [1, 2, 3];
const second = [4, 5, 6];
const combined = [...first, ...second];
console.log(combined);
// [1, 2, 3, 4, 5, 6]

You can also insert additional values while combining arrays.

const weekdays = ["Monday", "Tuesday"];
const allDays = ["Sunday", ...weekdays, "Wednesday"];
console.log(allDays);
// ["Sunday", "Monday", "Tuesday", "Wednesday"]

3.3 Adding Elements to an Array

Spread syntax can create a new array containing existing elements and additional values.

const fruits = ["Apple", "Banana"];
const updatedFruits = [...fruits, "Orange"];
console.log(updatedFruits);
// ["Apple", "Banana", "Orange"]

This approach is useful when adding items to React Native state without directly modifying the original array.

3.4 Spread Operator with Objects

Object spread copies enumerable own properties from an object into a new object.

const user = {
  name: "Aarav",
  age: 24
};

const copiedUser = { ...user };
console.log(copiedUser);
// { name: "Aarav", age: 24 }

3.5 Updating Object Properties

Spread syntax is commonly used to update a particular property while retaining other properties.

const user = {
  name: "Aarav",
  age: 24,
  city: "Mumbai"
};

const updatedUser = {
  ...user,
  age: 25
};

console.log(updatedUser);
// { name: "Aarav", age: 25, city: "Mumbai" }

The original object remains unchanged. If a property is specified more than once, the value from the later occurrence takes precedence.

const settings = {
  theme: "light",
  fontSize: 14
};

const updatedSettings = {
  ...settings,
  theme: "dark"
};

console.log(updatedSettings);
// { theme: "dark", fontSize: 14 }

3.6 Spread Operator in Function Calls

Spread syntax can pass the elements of an array as individual function arguments.

function add(a, b, c) {
  return a + b + c;
}

const values = [10, 20, 30];
console.log(add(...values));
// 60

3.7 Spread Operator with Strings

Strings are iterable, so spread syntax can expand a string into individual characters.

const word = "React";
const characters = [...word];
console.log(characters);
// ["R", "e", "a", "c", "t"]

3.8 Shallow Copy Limitation

Spread syntax creates a shallow copy, not a deep copy. Nested objects remain shared references unless they are copied separately.

const original = {
  name: "Aarav",
  address: {
    city: "Mumbai"
  }
};

const copy = { ...original };

console.log(copy !== original);
// true

console.log(copy.address === original.address);
// true

To update a nested object without changing the original nested reference, copy each level that needs to change.

const updated = {
  ...original,
  address: {
    ...original.address,
    city: "Pune"
  }
};

console.log(updated.address.city);
// Pune

console.log(original.address.city);
// Mumbai

3.9 Advantages of Spread Syntax

  • Creates new arrays and objects conveniently.
  • Combines arrays and object properties in a readable way.
  • Supports immutable state updates.
  • Passes array elements to functions.
  • Reduces repetitive copying code.

4. The Rest Parameter

The rest parameter also uses three dots (...), but it collects multiple values into a single array. It is commonly used in function definitions when the number of arguments is not fixed.

4.1 Basic Rest Parameter Example

function showNumbers(...numbers) {
  console.log(numbers);
}

showNumbers(10, 20, 30, 40);
// [10, 20, 30, 40]

The rest parameter collects all remaining arguments into an array named numbers.

4.2 Calculating a Sum

function sum(...numbers) {
  return numbers.reduce((total, number) => total + number, 0);
}

console.log(sum(10, 20));
// 30

console.log(sum(10, 20, 30, 40));
// 100

The function works with different numbers of arguments because the rest parameter collects them into an array.

4.3 Rest Parameter with Regular Parameters

Regular parameters can appear before a rest parameter.

function introduce(greeting, ...names) {
  console.log(greeting);
  console.log(names);
}

introduce("Welcome", "Aarav", "Priya", "Rohan");
// Welcome
// ["Aarav", "Priya", "Rohan"]

The rest parameter must be the last parameter in a function definition.

4.4 Rest Syntax in Array Destructuring

Rest syntax can collect the remaining array elements during destructuring.

const numbers = [10, 20, 30, 40, 50];

const [first, second, ...remaining] = numbers;

console.log(first);
// 10

console.log(second);
// 20

console.log(remaining);
// [30, 40, 50]

4.5 Rest Syntax in Object Destructuring

In object destructuring, rest syntax collects the properties that have not already been extracted.

const employee = {
  name: "Priya",
  role: "Developer",
  department: "Engineering",
  city: "Mumbai"
};

const { name, ...otherDetails } = employee;

console.log(name);
// Priya

console.log(otherDetails);
// { role: "Developer", department: "Engineering", city: "Mumbai" }

4.6 Rest Parameter Rules

  • A function can have only one rest parameter.
  • The rest parameter must appear last in the parameter list.
  • The collected values are stored in an array.
  • Rest parameters are useful for flexible function APIs.
  • Rest syntax in destructuring collects remaining elements or properties.

5. Spread vs Rest Operator

Spread and rest use the same three-dot syntax, but their purposes are different. The surrounding syntax determines how the dots behave.

Point Spread Rest
Purpose Expands values. Collects values.
Common usage Array literals, object literals, function calls. Function parameters and destructuring assignments.
Result Individual elements or properties are inserted into a target expression. Remaining values are collected into an array or object.
Example [...items] function test(...items)

5.1 Comparison Example

// Spread: expands an array
const numbers = [1, 2, 3];
const copy = [...numbers];

// Rest: collects function arguments
function display(...values) {
  console.log(values);
}

display(1, 2, 3);

Remember: spread expands an existing collection, while rest gathers multiple values into a collection.

6. Template Literals

Template literals are string literals enclosed in backticks (`). They allow developers to embed JavaScript expressions directly into strings using ${...}. They also support multiline strings without requiring special newline escape sequences.

6.1 Traditional String Concatenation

const name = "Aarav";
const message = "Hello, " + name + "!";

console.log(message);
// Hello, Aarav!

6.2 Using Template Literals

const name = "Aarav";
const message = `Hello, ${name}!`;

console.log(message);
// Hello, Aarav!

Template literals make dynamic strings easier to read, especially when a string contains multiple variables.

6.3 Embedding Expressions

Any valid JavaScript expression can be evaluated inside the interpolation syntax.

const a = 10;
const b = 20;

const message = `The total is ${a + b}.`;

console.log(message);
// The total is 30.

6.4 Using Functions Inside Template Literals

function getFullName(firstName, lastName) {
  return `${firstName} ${lastName}`;
}

const message = `Welcome, ${getFullName("Priya", "Sharma")}!`;

console.log(message);
// Welcome, Priya Sharma!

6.5 Multiline Strings

Template literals can contain line breaks directly.

const details = `Name: Priya
Course: React Native
Status: Enrolled`;

console.log(details);

This is more convenient than joining several quoted strings with newline characters.

6.6 Template Literals for API URLs

Template literals can build URLs using dynamic values. Always validate or encode user-supplied query values when constructing URLs.

const userId = 42;
const apiUrl = `https://api.example.com/users/${userId}`;

console.log(apiUrl);
// https://api.example.com/users/42

6.7 Template Literals in React Native

Template literals are useful when displaying dynamic text in React Native components.

import React from "react";
import { View, Text } from "react-native";

export default function WelcomeScreen() {
  const name = "Aarav";
  const course = "React Native";

  return (
    <View>
      <Text>{`Hello, ${name}!`}</Text>
      <Text>{`Welcome to ${course} training.`}</Text>
    </View>
  );
}

6.8 Displaying Prices and Calculated Values

const product = "Headphones";
const price = 1999;
const quantity = 2;
const total = price * quantity;

const summary = `Product: ${product}
Price: ₹${price}
Quantity: ${quantity}
Total: ₹${total}`;

console.log(summary);

6.9 Common Template Literal Mistakes

  • Using single quotes instead of backticks when interpolation is required.
  • Writing ${name} outside a template literal and expecting substitution.
  • Forgetting that expressions inside ${...} are evaluated as JavaScript.
  • Embedding untrusted text into generated HTML without appropriate escaping in environments where HTML is interpreted.

7. JavaScript Modules

Modules allow developers to split a large application into smaller files. Each module can define variables, functions, components, constants, or classes and export the functionality that other files need.

React Native projects commonly use JavaScript modules to separate screens, reusable components, API services, utility functions, and configuration values.

7.1 Why Modules Are Important

  • Organize application code into logical files.
  • Promote code reuse across screens and components.
  • Make testing and debugging easier.
  • Reduce unnecessary duplication.
  • Make large applications easier to maintain.
  • Clarify dependencies between files.

7.2 Named Exports

A named export allows a module to export one or more specifically named values.

File: mathUtils.js

export const add = (a, b) => a + b;

export const subtract = (a, b) => a - b;

export function multiply(a, b) {
  return a * b;
}

Import named exports using their exported names inside curly braces.

File: App.js

import { add, subtract, multiply } from "./mathUtils";

console.log(add(10, 5));
// 15

console.log(subtract(10, 5));
// 5

console.log(multiply(10, 5));
// 50

7.3 Default Exports

A module can have one default export. Default exports are often used when a file represents one main component or function.

File: greeting.js

export default function greeting(name) {
  return `Hello, ${name}!`;
}

File: App.js

import greeting from "./greeting";

console.log(greeting("Aarav"));
// Hello, Aarav!

The name used when importing a default export can differ from the original function name.

7.4 Named Export vs Default Export

Feature Named Export Default Export
Number per module Can export multiple named values. One default export per module.
Import syntax Usually uses curly braces. Does not use curly braces for the default binding.
Import name Must match the exported name unless aliased. Can be chosen by the importer.
Example export export const API_URL = "..." export default App
Example import import { API_URL } from "./config" import App from "./App"

7.5 Renaming Named Imports

You can use the as keyword to give an imported named export a local alias.

// File: calculations.js
export const add = (a, b) => a + b;

// File: App.js
import { add as calculateSum } from "./calculations";

console.log(calculateSum(5, 7));
// 12

7.6 Importing Multiple Exports

// File: userUtils.js
export const formatName = (name) => name.trim();

export const isValidName = (name) => name.trim().length > 0;

// File: App.js
import { formatName, isValidName } from "./userUtils";

console.log(formatName(" Priya "));
console.log(isValidName("Priya"));

7.7 Exporting at the End of a File

You can define functions or constants first and export them together at the end of the module.

const API_VERSION = "v1";

function getApiVersion() {
  return API_VERSION;
}

export { API_VERSION, getApiVersion };

7.8 Re-exporting Values

A module can re-export functionality from another module. This pattern is useful when creating a central export file, often called a barrel file.

// File: components/Button.js
export default function Button() {
  return null;
}

// File: components/index.js
export { default as Button } from "./Button";

Another file can import the component using the central file:

import { Button } from "./components";

Barrel files can simplify imports, but overly broad re-exports may make dependencies harder to trace or affect bundling in some project setups.

8. Creating Reusable Modules in React Native

A React Native application often separates UI components, screens, utility functions, and API logic into different files. Each file can export its reusable functionality for other modules to import.

8.1 Example Project Structure

MyReactNativeApp/
├── App.js
├── components/
│   └── WelcomeCard.js
├── screens/
│   └── HomeScreen.js
├── utils/
│   └── formatName.js
└── services/
    └── api.js

8.2 Creating a Reusable Component

File: components/WelcomeCard.js

import React from "react";
import { View, Text } from "react-native";

export default function WelcomeCard({ name, course }) {
  return (
    <View>
      <Text>{`Hello, ${name}!`}</Text>
      <Text>{`Course: ${course}`}</Text>
    </View>
  );
}

8.3 Importing the Component

File: App.js

import React from "react";
import { View } from "react-native";
import WelcomeCard from "./components/WelcomeCard";

export default function App() {
  return (
    <View>
      <WelcomeCard name="Aarav" course="React Native" />
    </View>
  );
}

In this example, the component uses object destructuring to read props and template literals to display dynamic text. The component is exported as the default export and imported into the main application file.

9. Using Spread Syntax with React Native Props

Spread syntax can pass multiple object properties as props to a component. This can reduce repetitive code when a component accepts many properties.

const user = {
  name: "Priya",
  role: "Developer"
};

// Example component usage:
<ProfileCard {...user} />

The example assumes a ProfileCard component that accepts name and role props.

function ProfileCard({ name, role }) {
  return (
    <View>
      <Text>{name}</Text>
      <Text>{role}</Text>
    </View>
  );
}

Only spread trusted, intentional properties into components. Avoid forwarding unrelated properties or values that a component should not receive.

10. Updating React Native State with Spread Syntax

React state should be updated by creating new arrays or objects rather than directly mutating the existing state. Spread syntax is a common technique for making these immutable updates.

10.1 Updating Object State

import React, { useState } from "react";
import { View, Text, Button } from "react-native";

export default function ProfileScreen() {
  const [user, setUser] = useState({
    name: "Aarav",
    age: 24
  });

  const updateAge = () => {
    setUser(previousUser => ({
      ...previousUser,
      age: previousUser.age + 1
    }));
  };

  return (
    <View>
      <Text>{`Name: ${user.name}`}</Text>
      <Text>{`Age: ${user.age}`}</Text>
      <Button title="Increase Age" onPress={updateAge} />
    </View>
  );
}

The functional state updater receives the latest previous state and returns a new object containing the updated age and the unchanged properties.

10.2 Adding an Item to Array State

const [tasks, setTasks] = useState(["Study JavaScript"]);

const addTask = () => {
  setTasks(previousTasks => [
    ...previousTasks,
    "Practice React Native"
  ]);
};

10.3 Updating an Item in Array State

const [tasks, setTasks] = useState([
  { id: "1", title: "Learn JavaScript", completed: false },
  { id: "2", title: "Learn React Native", completed: false }
]);

const completeTask = (taskId) => {
  setTasks(previousTasks =>
    previousTasks.map(task =>
      task.id === taskId
        ? { ...task, completed: true }
        : task
    )
  );
};

This example creates a new array and a new object for the changed task. The other task objects are retained because they do not need to change.

11. Combining ES6+ Features in One Example

The following example demonstrates template literals, object spread, array spread, destructuring, and reusable functions together.

const students = [
  { id: 1, name: "Aarav", score: 85 },
  { id: 2, name: "Priya", score: 92 }
];

function createStudent(name, ...scores) {
  const average = scores.length
    ? scores.reduce((total, score) => total + score, 0) / scores.length
    : 0;

  return {
    name,
    average
  };
}

const newStudent = createStudent("Rohan", 80, 90, 100);

const updatedStudents = [
  ...students,
  { id: 3, ...newStudent }
];

updatedStudents.forEach(({ name, score, average }) => {
  const result = score ?? average;
  console.log(`${name}: ${result}`);
});

The original student objects do not contain an average property, so this example uses the nullish coalescing operator to fall back to average. The destructured score and average variables may be undefined when the corresponding property is absent.

12. Common Errors and How to Fix Them

Error Reason Solution
Incorrect spread syntax Using three dots where the expression does not support spread. Check the surrounding array, object, or function-call syntax.
Rest parameter not last A rest parameter is followed by another parameter. Move the rest parameter to the end.
Wrong import name A named import does not match the exported name. Check the export name or use an alias with as.
Wrong default import syntax A default export is imported using named-import syntax. Use a default import without curly braces.
Incorrect module path The relative path or filename is incorrect. Check the file location and path spelling.
State mutation An existing array or object is changed directly. Create a new array or object using spread syntax or other immutable operations.
Unexpected nested changes A shallow copy shares nested object references. Copy the nested objects that need to change.
Interpolation does not work Single or double quotes are used instead of backticks. Use backticks and place expressions inside ${...}.
Unexpected overwritten property A later object spread or property definition uses the same key. Check the property order and intended precedence.

13. Best Practices

  • Use spread syntax when creating a new array or object from existing data.
  • Prefer immutable state updates in React Native components.
  • Remember that spread creates a shallow copy rather than a deep copy.
  • Use rest parameters when a function needs to accept a variable number of arguments.
  • Choose clear names for rest parameters, such as ...items or ...values.
  • Use template literals for readable dynamic strings and multiline text.
  • Use named exports when a module exposes multiple related utilities.
  • Use default exports when a file has one primary exported component or value.
  • Keep import paths accurate and consistent with the project's file structure.
  • Separate components, API services, constants, and utility functions into logical modules.
  • Avoid spreading large objects into components when only a few properties are required.
  • Use the project's configured JavaScript and React Native tooling to verify compatibility with supported syntax.

14. Practical Exercises

Exercise 1: Copy an Array

Create an array of five numbers and use spread syntax to copy it into another array. Confirm that the arrays are different references.

Exercise 2: Merge Arrays

Create two arrays of programming languages and combine them into one array using the spread operator.

Exercise 3: Update an Object

Create an object containing a person's name, age, and city. Create a new object with an updated city while preserving the other properties.

Exercise 4: Create a Flexible Sum Function

Write a function that accepts any number of numeric arguments using a rest parameter and returns their sum.

Exercise 5: Build a Template Literal

Create variables for a student's name, course, and score. Use a template literal to generate a formatted summary.

Exercise 6: Create a Utility Module

Create a file called stringUtils.js that exports two named functions: one that converts text to uppercase and another that counts characters. Import and test both functions in another file.

Exercise 7: Build a Reusable React Native Component

Create a reusable profile component that receives a name, role, and city as props. Use destructuring and template literals to display the details.

15. Mini Project: Student Profile Manager

Project objective: Create a small React Native application that displays student information and demonstrates spread syntax, rest parameters, template literals, and modules.

15.1 Requirements

  • Create a reusable student card component.
  • Store student information in an array of objects.
  • Add a new student by creating a new array with spread syntax.
  • Update a student's details without mutating the original object.
  • Use template literals to display a personalized greeting.
  • Move student-related utility functions into a separate module.
  • Use named or default exports to share functionality between files.

15.2 Example Utility Module

File: utils/studentUtils.js

export function formatStudentName(name) {
  return name.trim();
}

export function createStudent(name, ...subjects) {
  return {
    id: String(Date.now()),
    name: formatStudentName(name),
    subjects
  };
}

15.3 Example Component

File: components/StudentCard.js

import React from "react";
import { View, Text } from "react-native";

export default function StudentCard({ student }) {
  const { name, subjects = [] } = student;

  return (
    <View>
      <Text>{`Student: ${name}`}</Text>
      <Text>{`Subjects: ${subjects.join(", ")}`}</Text>
    </View>
  );
}

15.4 Expected Learning Outcome

After completing this project, learners should understand how modern JavaScript syntax improves code organization, enables reusable functionality, and supports safer updates to application data.

16. Interview Questions and Answers

Q1. What is the spread operator?

Answer: The spread operator uses ... to expand elements of an iterable or enumerable own properties of an object into a target expression.

Q2. What is the rest parameter?

Answer: The rest parameter collects the remaining function arguments into an array.

Q3. What is the main difference between spread and rest?

Answer: Spread expands a collection, while rest collects multiple values into a collection. Their syntax is the same, but their roles depend on context.

Q4. Can spread syntax copy an array?

Answer: Yes. For example, const copy = [...original] creates a new array containing the original array's elements. The copy is shallow.

Q5. What is a shallow copy?

Answer: A shallow copy creates a new outer array or object, but nested objects and arrays may still be shared references.

Q6. Why is spread syntax useful in React Native?

Answer: It helps create immutable state updates, merge data, add items to arrays, update object properties, and pass multiple props to components.

Q7. What are template literals?

Answer: Template literals are strings enclosed in backticks. They support expression interpolation with ${...} and allow multiline strings.

Q8. How do you insert a variable into a template literal?

Answer: Use the variable inside ${...}, such as `Hello, ${name}!`.

Q9. What is a JavaScript module?

Answer: A module is a file that can export functionality and import functionality from other files, helping organize and reuse code.

Q10. What is the difference between named and default exports?

Answer: A module can have multiple named exports, imported by name, and one default export, imported using a chosen local name.

Q11. How do you import a named export?

Answer: Use curly braces, for example, import { add } from "./mathUtils".

Q12. How do you import a default export?

Answer: Import it without curly braces, for example, import WelcomeCard from "./WelcomeCard".

Q13. Why should React state not be mutated directly?

Answer: React relies on state updates to determine when to render components. Creating new arrays or objects helps preserve predictable updates and avoids unintended side effects.

Q14. Can a function have more than one rest parameter?

Answer: No. A function definition can contain only one rest parameter, and it must be the final parameter.

Q15. What is the purpose of a utility module?

Answer: A utility module groups reusable functions, such as formatting, validation, calculations, and data transformation, so multiple parts of an application can use them.

17. Quick Revision Checklist

  • Spread syntax expands elements or object properties.
  • Rest syntax collects remaining values.
  • Array spread can copy and combine arrays.
  • Object spread can copy and merge object properties.
  • Spread copies are shallow unless nested structures are copied separately.
  • Rest parameters collect function arguments into an array.
  • Template literals use backticks.
  • Template literal interpolation uses ${...}.
  • JavaScript modules support code reuse through imports and exports.
  • Named imports use curly braces and match exported names unless aliased.
  • Default imports do not use curly braces.
  • React Native state updates should create new arrays or objects instead of mutating existing state.
  • Reusable modules make applications easier to maintain and test.

18. Additional Learning Resources

19. Conclusion

ES6+ features make JavaScript development more expressive and maintainable. The spread operator expands arrays and object properties, while rest syntax collects remaining values. Template literals simplify dynamic and multiline strings, and modules help divide an application into reusable files.

In React Native, these features are especially valuable when building reusable components, managing props, updating state immutably, formatting dynamic text, and separating application logic into screens, utilities, and services. Regular practice with these concepts builds a strong foundation for developing modern React Native applications.

Continue Learning: Explore the React Native Training Course and register for a course demo to continue developing your mobile application skills.

whatsapp